﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UniLua;
using System;
using System.Reflection;
using System.Text;

namespace TCG.FFI
{
	/// <summary>
	/// 提供游戏内调试功能给lua调用，用在command窗口中。
	/// </summary>

	public static class GameDebugToolsLib 
	{
		public static string LIB_NAME = "GameDebugToolsLib";

		public static int lf_ShowLogWindow (ILuaState luaState)
		{
			DebugWindow.instance.logWindowEnabled = true;
			return 0;
		}

		public static int lf_HideLogWindow (ILuaState luaState)
		{
			DebugWindow.instance.logWindowEnabled = false;
			return 0;
		} 

		public static int lf_LoadTexture (ILuaState luaState)
        {
            uint assetId = luaState.ToUnsigned (-1);
			AssetRequest ar = new AssetRequest (assetId, AssetType.UnityAssetBundle, delegate (AssetRequest request) {
				if (string.IsNullOrEmpty (request.error))
				{
					GameObject go = GameObject.CreatePrimitive (PrimitiveType.Cube);
					go.renderer.material.mainTexture = request.GetResultAsset<Texture> ().asset;
				}
				else
				{
					Debug.LogError (request.error);
				}
			});
			ar.Request <Texture> ();
            return 0;
        }

		public static int lf_LoadMaterial (ILuaState luaState)
        {
			uint assetId = luaState.ToUnsigned (-1);
			new AssetRequest (assetId, AssetType.ProtoStream, delegate (AssetRequest request) {
				if (string.IsNullOrEmpty (request.error))
				{
					GameObject go = GameObject.CreatePrimitive (PrimitiveType.Cube);
					go.renderer.sharedMaterial = request.GetResultAsset<Material> ().asset;
				}
				else
				{
					Debug.LogError (request.error);
				}
			}).Request<Material> ();

            return 0;
        }

		public static int lf_LoadPrefab (ILuaState luaState)
        {
			uint assetId = luaState.ToUnsigned (-1);
			new AssetRequest (assetId, AssetType.UnityAssetBundle, delegate (AssetRequest request) {
				if (string.IsNullOrEmpty (request.error))
				{
					GameObject prefab = request.GetResultAsset<GameObject> ().asset;
					GameObject.Instantiate (prefab);
				}
				else
				{
					Debug.LogError (request.error);
				}
			}).Request<GameObject> ();

			return 0;
        }

		public static int lf_GetModel (ILuaState luaState)
		{
			uint assetId = luaState.ToUnsigned (1);
			string name = luaState.ToString (2);
			GameModelPool.instance.GetModel (assetId, delegate (GameModelPooled result) {
				result.gameObject.SetActive (true);
				result.gameObject.name = name;
			});
			return 0;
		}

		public static int lf_ReleaseModel (ILuaState luaState)
		{
			string name = luaState.ToString (1);
			GameModelPooled[] list = GameObject.FindObjectsOfType<GameModelPooled> ();
			for (int i = 0, len = list.Length; i < len; ++ i)
			{
				if (list[i].gameObject.name == name)
				{
					list[i].gameObject.SetActive (false);
					GameModelPool.instance.ReleaseModel (list[i]);
				}
			}

			return 0;
		}

		public static int lf_ReleaseModelAll (ILuaState luaState)
		{
			GameModelPooled[] list = GameObject.FindObjectsOfType<GameModelPooled> ();
			for (int i = 0, len = list.Length; i < len; ++ i)
			{
				list[i].gameObject.SetActive (false);
				GameModelPool.instance.ReleaseModel (list[i]);
			}
			return 0;
		}

		public static int lf_DestroyModelFreed (ILuaState luaState)
		{
			GameModelPool.instance.DestroyAllFreed ();
			return 0;
		}
		
		public static int lf_PrintModelpoolStatus (ILuaState luaState)
		{
			uint assetId = luaState.ToUnsigned (1);

			GameModelPool modelPool = GameModelPool.instance;
			System.Type t = modelPool.GetType ();
			FieldInfo fi = t.GetField ("m_freedModelTable", BindingFlags.NonPublic | BindingFlags.Instance);
			IDictionary<uint, IList<GameModelPooled>> freedModelTable = fi.GetValue (modelPool) as IDictionary<uint, IList<GameModelPooled>>;
			fi = t.GetField ("m_usingModelTable", BindingFlags.NonPublic | BindingFlags.Instance);
			IDictionary<uint, IList<GameModelPooled>> usingModelTable = fi.GetValue (modelPool) as IDictionary<uint, IList<GameModelPooled>>;

			StringBuilder sb = new StringBuilder ();
			sb.AppendLine ("* GameModelPool Status ************************************");
			if (assetId == 0)
			{
				System.Collections.Generic.HashSet<uint> set = new HashSet<uint> ();
				set.UnionWith (freedModelTable.Keys);
				set.UnionWith (usingModelTable.Keys);

				if (set.Count > 0)
				{
					foreach (uint prefabId in set)
					{
						drawModelPoolStatus (prefabId, freedModelTable, usingModelTable, sb);
					}
				}
				else
				{
					sb.AppendLine ("** Nothing found.");
				}
			}
			else
			{
				drawModelPoolStatus (assetId, freedModelTable, usingModelTable, sb);
			}
			Debug.Log (sb.ToString ());
			return 0;
		}

		static void drawModelPoolStatus (uint prefabId, IDictionary<uint, IList<GameModelPooled>> freedModelTable,
		                                 IDictionary<uint, IList<GameModelPooled>> usingModelTable, StringBuilder sb)
		{
			// * [prefabId]
			sb.Append ("* [");
			sb.Append (prefabId);
			sb.AppendLine ("]");

			// ** Freed: count
			sb.Append ("** Freed: ");
			if (freedModelTable.ContainsKey (prefabId))
			{
				sb.Append (freedModelTable[prefabId].Count);
				sb.AppendLine ();
			}
			else
			{
				sb.AppendLine ("0");
			}

			// ** Used: count [ name, name, ...]
			sb.Append ("** Using: ");
			if (usingModelTable.ContainsKey (prefabId))
			{
				sb.Append (usingModelTable[prefabId].Count);
				if (usingModelTable[prefabId].Count > 0)
				{
					sb.Append (" [");
					for (int i = 0,len = usingModelTable[prefabId].Count; i < len; ++ i)
					{
						sb.Append (usingModelTable[prefabId][i].gameObject.name);
						if (i < len - 1)
						{
							sb.Append (", ");
						}
					}
					sb.AppendLine ("]");
				}
				else
				{
					sb.AppendLine ();
				}
			}
			else
			{
				sb.AppendLine ("0");
			}
		}

		public static int lf_PrintTextureInfo (ILuaState luaState)
		{
			StringBuilder sb = new StringBuilder ();
			sb.AppendLine ("* GameTextureDatabase Status ************************************");

			uint assetId = luaState.ToUnsigned (-1);
			GameTextureDatabase textureDB = GameAssetsDatabase.instance.textureDatabase;
			System.Type t = textureDB.GetType ();
			FieldInfo fi = t.GetField ("m_cachedAssets", BindingFlags.NonPublic | BindingFlags.Instance);
			IDictionary<uint, GameAsset<Texture>> cachedAssets = fi.GetValue (textureDB) as IDictionary<uint, GameAsset<Texture>>;
			if (assetId == 0)
			{
				if (cachedAssets.Count > 0)
				{
					sb.Append ("* 已加载贴图: ");
					sb.AppendLine (cachedAssets.Count.ToString ());

					foreach (GameAsset<Texture> _value in cachedAssets.Values)
					{
						sb.Append("** ");
						sb.AppendLine (_value.ToString ());
					}
				}
				else
				{
					sb.AppendLine ("* 未加载贴图");
				}
			}
			else 
			{
				if (cachedAssets.ContainsKey (assetId))
				{
					GameAsset<Texture> asset = cachedAssets[assetId];
					sb.Append ("* ");
					sb.AppendLine (asset.ToString ());
				}
				else
				{
					sb.AppendLine (string.Format ("* 贴图{0}尚未加载", assetId));
				}
			}

			Debug.Log (sb.ToString ());

			return 0;
		}

		public static int lf_PrintMaterialInfo (ILuaState luaState)
		{
			StringBuilder sb = new StringBuilder ();
			sb.AppendLine ("* GameMaterialDatabase Status ************************************");

			uint assetId = luaState.ToUnsigned (-1);
			GameMaterialDatabase materialDB = GameAssetsDatabase.instance.materialDatabase;
			System.Type t = materialDB.GetType ();
			FieldInfo fi = t.GetField ("m_cachedAssets", BindingFlags.NonPublic | BindingFlags.Instance);
			IDictionary<uint, GameAsset<Material>> cachedAssets = fi.GetValue (materialDB) as IDictionary<uint, GameAsset<Material>>;
			if (assetId == 0)
			{
				if (cachedAssets.Count > 0)
				{
					sb.Append ("* 已加载材质: ");
					sb.AppendLine (cachedAssets.Count.ToString ());
					
					foreach (GameAsset<Material> _value in cachedAssets.Values)
					{
						sb.Append ("** ");
						sb.AppendLine (_value.ToString ());
					}
				}
				else
				{
					sb.AppendLine ("* 未加载材质");
				}
			}
			else 
			{
				if (cachedAssets.ContainsKey (assetId))
				{
					GameAsset<Material> asset = cachedAssets[assetId];
					sb.Append ("* ");
					sb.AppendLine (asset.ToString ());
				}
				else
				{
					sb.AppendLine (string.Format ("* 材质{0}尚未加载", assetId));
				}
			}
			Debug.Log (sb.ToString ());
			
			return 0;
		}

		public static int lf_PrintPrefabInfo (ILuaState luaState)
		{
			StringBuilder sb = new StringBuilder ();
			sb.AppendLine ("* GamePrefabDatabase Status ************************************");

			uint assetId = luaState.ToUnsigned (-1);
			GamePrefabDatabase prefabDB = GameAssetsDatabase.instance.prefabDatabase;
			System.Type t = prefabDB.GetType ();
			FieldInfo fi = t.GetField ("m_cachedAssets", BindingFlags.NonPublic | BindingFlags.Instance);
			IDictionary<uint, GameAsset<GameObject>> cachedAssets = fi.GetValue (prefabDB) as IDictionary<uint, GameAsset<GameObject>>;
			if (assetId == 0)
			{
				if (cachedAssets.Count > 0)
				{

					sb.Append ("* 已加载预设: ");
					sb.AppendLine (cachedAssets.Count.ToString ());
					
					foreach (GameAsset<GameObject> _value in cachedAssets.Values)
					{
						sb.Append ("** ");
						sb.AppendLine (_value.ToString ());
					}
				}
				else
				{
					sb.AppendLine ("* 未加载预设");
				}
			}
			else 
			{
				if (cachedAssets.ContainsKey (assetId))
				{
					GameAsset<GameObject> asset = cachedAssets[assetId];
					sb.AppendLine ("* ");
					sb.AppendLine (asset.ToString ());
				}
				else
				{
					sb.AppendLine (string.Format ("* 预设{0}尚未加载", assetId));
				}
			}
			Debug.Log (sb.ToString ());

			return 0;
		}

		public static int lf_UnloadUnusedAssets (ILuaState luaState)
		{
			GameAssetsDatabase.instance.UnloadUnusedAssets ();
			return 0;
		}

		public static int lf_UnloadUnusedTextures (ILuaState luaState)
		{
			GameAssetsDatabase.instance.textureDatabase.UnloadUnusedAssets ();
			return 0;
		}

		public static int lf_UnloadUnusedMaterials (ILuaState luaState)
		{
			GameAssetsDatabase.instance.materialDatabase.UnloadUnusedAssets ();
			return 0;
		}

		public static int lf_UnloadUnusedPrefabs (ILuaState luaState)
		{
			GameAssetsDatabase.instance.prefabDatabase.UnloadUnusedAssets ();
			return 0;
		}

		public static int lf_GC (ILuaState luaState)
		{
			Resources.UnloadUnusedAssets ();
			System.GC.Collect ();

			return 0;
		}
	}
}